package com.zzgc.modules.controller;

import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * websocket 连接
 * @Author:
 * @CreateTime: 2022-09-17  17:02
 * @Description:
 * @Version: 1.0
 */
@ServerEndpoint("/ws/{myWebsocket}")
@Component
public class WsController {

    //用以下代码替换注释掉的代码,问题解决
//    private static UserService userService;
//    @Autowired
//    public void setPlanmecaScreenService(UserService userService){
//        WebsocketController.userService = userService;
//    }

    //静态变量，用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;

    public static Map<String, List<Session>> clients = new ConcurrentHashMap<String, List<Session>>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session session;

    //concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话，可以使用Map来存放，其中Key可以为用户标识
    private static ConcurrentHashMap<String, WsController> webSocketSet = new ConcurrentHashMap<String, WsController>();

    //与某个客户端的连接会话，需要通过它来给客户端发送数据
    private Session WebSocketsession;

    String myWebsocket = "";

    /**
     *  连接建立成功调用的方法
     * @param myWebsocket
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("myWebsocket") String myWebsocket, Session session){
        System.out.println("myWebsocket = " + myWebsocket);
        //接收到发送消息的人员编号
        myWebsocket = myWebsocket;
        this.WebSocketsession = session;
        this.session = session;

        List<Session> sessions = null;
        if(clients.get(myWebsocket) != null){
            sessions = clients.get(myWebsocket);
            sessions.add(session);
        }else{
            sessions = new ArrayList<Session>();
            sessions.add(session);
        }
        clients.put(myWebsocket, sessions);
        System.out.println("clients = " + clients);
        //加入map中
        webSocketSet.put(myWebsocket, this);
        System.out.println("webSocketSet = " + webSocketSet);
        addOnlineCount();//在线数加1
        System.out.println("有新连接加入！当前在线人数为" + getOnlineCount());
    }

    /**
     * 收到客户端消息时触发
     * @param myWebsocket
     * @param message
     * @return
     */
    @OnMessage
    public void onMessage(@PathParam("myWebsocket") String myWebsocket, String message) {
        System.out.println("来自客户端"+myWebsocket+"的消息:" + message);
        sendMessage(myWebsocket,message);
//        return "Got your message ("+ message +").Thanks !";
    }

    /**
     * 异常时触发
     * @param myWebsocket
     * @param throwable
     */
    @OnError
    public void onError(@PathParam("myWebsocket") String myWebsocket, Throwable throwable) {
//        logger.info("Websocket Connection Exception:" + myWebsocket);
//        logger.info(throwable.getMessage(), throwable);
//        java.util.concurrent.TimeoutException
        System.out.println("异常: " + myWebsocket + " -> "+throwable.getMessage());
        clients.remove(myWebsocket);
    }

    /**
     * 关闭连接时触发
     * @param myWebsocket
     */
    @OnClose
    public void onClose(@PathParam("myWebsocket") String myWebsocket) {
//        logger.info("Websocket Close Connection:" + myWebsocket);
        subOnlineCount();
        System.out.println("有连接退出！当前在线人数为" + getOnlineCount());
        clients.remove(myWebsocket);
    }

    /**
     * 将数据传回客户端
     * 异步的方式 -- 发送信息
     * @param myWebsocket
     * @param message
     */
    public static void broadcast(String myWebsocket, String message) {
        if (clients.containsKey(myWebsocket)) {
//            clients.get(myWebsocket).getAsyncRemote().sendText(message);
            List<Session> sessions = clients.get(myWebsocket);
            for(Session sess : sessions){
                //System.out.println("message = " + message);
                // 信息传输
                 sess.getAsyncRemote().sendText(message);
            }
        } else {
            System.out.println("没有 " + myWebsocket+" 连接!");
            //throw new NullPointerException("[" + myWebsocket +"]Connection does not exist");
        }
    }

    /**
     * 将数据传回客户端
     * 同步的方式 -- 发送文件
     * @param myWebsocket
     * @param path
     */
    public static void broadcastFile(String myWebsocket, String path) throws IOException {
        if (clients.containsKey(myWebsocket)) {

            List<Session> sessions = clients.get(myWebsocket);
            for(Session sess : sessions){
                System.out.println("message path = " + path);
                // 文件传输
                File[] files = new File(path).listFiles();
                try {
                    // 给文件夹内试卷排序 1-24 顺序打印
                    List fileList = Arrays.asList(files);
                    Collections.sort(fileList, new Comparator<File>() {
                        @Override
                        public int compare(File o1, File o2) {
                            if (o1.isDirectory() && o2.isFile())
                                return -1;
                            if (o1.isFile() && o2.isDirectory())
                                return 1;
                            int o2s = Integer.parseInt(o2.getName().substring(0, o2.getName().indexOf("_")));
                            int o1s = Integer.parseInt(o1.getName().substring(0, o1.getName().indexOf("_")));
                            return o1s - o2s;
                        }
                    });
                } catch (Exception e) {
                    e.printStackTrace();
                }
                for (File file : files) {
                    InputStream is= new FileInputStream(file);
                    ByteArrayOutputStream out= new ByteArrayOutputStream();

                    int count = 0;
                    // 网络传输时数据块不能太大, 接收端容易超时
                    byte[] b = new byte[1024];
                    while( (count=is.read(b)) != -1 ){
                        out.write(b,0, count);
                    }
                    ByteBuffer wrap = ByteBuffer.wrap(out.toByteArray());
                    // 同步调用, 异步会报异常 The remote endpoint was in state [BINARY_FULL_WRITING] which is an invalid state for called method
                    sess.getBasicRemote().sendBinary(wrap);
                    is.close();
                }
            }
        } else {
            System.out.println("没有 " + myWebsocket+" 连接!");
            throw new NullPointerException("[" + myWebsocket +"]Connection does not exist");
        }
    }

    public static synchronized int getOnlineCount() {
        //返回在线人数
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        //在线人数+1
        WsController.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        //在线人数-1
        WsController.onlineCount--;
    }

    public void sendMessage(String myWebsocket, String message) {
        synchronized(webSocketSet.get(myWebsocket)) {
            //根據手機號查詢用戶信息 並轉成json
//            UserPO user = userService.getUserByPhone(myWebsocket);
//            CommonResponse<UserPO> common = new CommonResponse<UserPO>(ResponseTypeEnums.SUCCESS, null, null, user);
//            String json= JSON.toJSONString(common);

            List<Session> sessions = clients.get(myWebsocket);
            for(Session sess : sessions){
                try {
//                    sess.getBasicRemote().sendText(json);
                    sess.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
